import java.lang.reflect.*;

public class example1
{
   public static void main(String[] args) throws SecurityException, IllegalArgumentException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchFieldException
   {
		Employee emp=new Employee();
		Class example=null;
		//There are three ways of creating a class instance:
		try
		{
			if (args.length==1)
				example = Class.forName(args[0]);
			else
			{
				example = emp.getClass();
				//Class example = Employee.class;
			}
		}
		catch (ClassNotFoundException e)
		{
			System.out.println("Class not found");
			System.exit(-1);
		} 
		printClassName(example);
		printSuperClass(example);
		printMods(example);
		printFields(example);
		printConstructors(example);
		printMethods(example);
		
		useCons(example);
		changeSalary(example);
	}

   public static void printClassName(Class example)
   {
	   System.out.println( "Class name: " + example.getName());
   }
   
   public static void printSuperClass(Class example)
   {
	   Class superC=example.getSuperclass();
	   System.out.println("The super classes for this class are: ");
	   while (superC!=null)
	   {
		   System.out.println("\t" + example.getSuperclass());
		   superC=superC.getSuperclass();
	   }
   }
   
   public static void printMods(Class example)
   {
	   int mods = example.getModifiers();
	   System.out.println("Class is public: " + Modifier.isPublic(mods));
	   System.out.println("Class is final: " +  Modifier.isFinal(mods));
	   System.out.println("Class is abstract: " + Modifier.isAbstract(mods));
	   System.out.println("Interface: " + Modifier.isInterface(mods));
   }
   
   public static void printFields(Class example)
   {
	   System.out.println("Declared fields are:");
	   Field[] fields = example.getDeclaredFields();
	   for (Field field : fields)
		   System.out.println("\tName: "+field.getName()+", Type: "+field.getType());
   }
   
   public static void printConstructors(Class example)
   {
	   System.out.println("Declared Constructors are:");
	   for (Constructor con : example.getDeclaredConstructors())
	   {
		   Class[] parameterTypes = con.getParameterTypes();
		   System.out.print("\t[ ");
		   for (Class type : parameterTypes)
			   System.out.print(type.getName() + " ");
		   System.out.println("]");
	   }
   }
   
   public static void printMethods(Class example)
   {
	   System.out.println("Declared Methods are:");
	   Method[] methods = example.getDeclaredMethods();
	   for (Method method : methods)
	   {
		   System.out.println("\tName: " + method.getName());
		   System.out.println("\t\tReturn type: " + method.getReturnType().getName());
		   Class[] parameters = method.getParameterTypes();
		   System.out.print("\t\tParameter Types: [");
		   for (Class param : parameters)
			   System.out.print(" " + param.getName());
		   System.out.println(" ]");
	   }
   }
   
   public static void useCons(Class example) throws SecurityException, NoSuchMethodException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException
   {
	   Class[] parameters ={String.class, String.class, Integer.TYPE };
	   Constructor cons = example.getConstructor(parameters);
	   System.out.println("Found the constructor: " + cons);
	   Object[] args1 = {"Moses","The prophet",new Integer(20000)};
	   Object newObject = cons.newInstance(args1);
	   System.out.println("New object: " +newObject);
   }
   
   public static void changeSalary(Class example) throws SecurityException, NoSuchMethodException, NoSuchFieldException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException
   {
	   System.out.println("This will change the salary");
	   Class[] cParameters = {Integer.TYPE };
	   Method setSalaryMethod = example.getMethod("setSalary", cParameters);
	   Field salary=example.getDeclaredField("salary");
	   Object newObject = example.newInstance();
	   
	   salary.setAccessible(true);
	   
	   Object oSalary = salary.get(newObject);
	   System.out.println("\tOld salary: "+oSalary);
	   Object[] oParameters = {new Integer(100000)};
	   setSalaryMethod.invoke(newObject, oParameters);
	   oSalary=salary.get(newObject);
	   System.out.println("\tnew salary: "+oSalary);
	   salary.set(newObject, 0);
	   oSalary=salary.get(newObject);
	   System.out.println("\tcurrent salary: "+oSalary);
   }
}

